package com.xuelang.pipeline.worker.app.crd.tekton.impl;

import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.xuelang.pipeline.worker.app.common.util.K8sUtils;
import com.xuelang.pipeline.worker.app.common.util.OffsetDateTimeAdapter;
import com.xuelang.pipeline.worker.app.common.util.VerifyUtil;
import com.xuelang.pipeline.worker.app.crd.tekton.TektonPipelineService;
import com.xuelang.pipeline.worker.client.crd.dto.PipelineDTO;
import com.xuelang.pipeline.worker.client.crd.dto.PipelineRunDTO;
import com.xuelang.pipeline.worker.client.crd.tekton.v1beta.V1Beta1ParamSpec;
import com.xuelang.pipeline.worker.client.crd.tekton.v1beta.V1Beta1WorkspaceBinding;
import com.xuelang.pipeline.worker.client.crd.tekton.v1beta.V1PipelineList;
import com.xuelang.pipeline.worker.client.crd.tekton.v1beta.V1PipelineRunList;
import com.xuelang.pipeline.worker.client.crd.tekton.v1beta.common.Param;
import com.xuelang.pipeline.worker.client.crd.tekton.v1beta.common.ParamValue;
import com.xuelang.pipeline.worker.client.crd.tekton.v1beta.pipeline.*;
import com.xuelang.pipeline.worker.client.crd.tekton.v1beta.task.V1Beta1TaskRef;
import io.kubernetes.client.custom.V1Patch;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.apis.CustomObjectsApi;
import io.kubernetes.client.openapi.models.V1ObjectMeta;
import io.kubernetes.client.openapi.models.V1PersistentVolumeClaimVolumeSource;
import io.kubernetes.client.openapi.models.V1SecretVolumeSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Type;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;


/**
 * @author liuyuan.ly
 * @since 2024/5/30 15:12
 */
@Service
@Slf4j
public class TektonPipelineServiceImpl implements TektonPipelineService {


    @Override
    public V1Beta1Pipeline saveOrUpdateTektonPipeline(PipelineDTO pipeline) {
        VerifyUtil.verifyStringNotBlank(pipeline.getNamespaceName(), "未获取到命名空间的信息");
        VerifyUtil.verifyStringNotBlank(pipeline.getV1Beta1PipelineStr(), "未获取流水线信息");
        K8sUtils.initApiClient(pipeline.getKubeConfig());

        // mock
//        V1Beta1Pipeline v1Beta1Pipeline = getV1Beta1Pipeline(pipeline);
        String v1Beta1PipelineStr = pipeline.getV1Beta1PipelineStr();
        V1Beta1Pipeline v1Beta1Pipeline = JSON.parseObject(v1Beta1PipelineStr, V1Beta1Pipeline.class);
        System.out.println(JSON.toJSONString(v1Beta1Pipeline));

        pipeline.setPipelineName(v1Beta1Pipeline.getMetadata().getName());
        V1PipelineList tektonPipeline = getTektonPipeline(pipeline);


        CustomObjectsApi customObjectsApi = new CustomObjectsApi();
        Object object = null;
        try {
            if (CollectionUtils.isEmpty(tektonPipeline.getItems())) {
                //未查询到则创建，无则更新
                object = customObjectsApi.createNamespacedCustomObject(
                        "tekton.dev",
                        "v1beta1",
                        pipeline.getNamespaceName(),
                        "pipelines",
                        v1Beta1Pipeline, null, null, null
                );
            } else {

                V1Beta1Pipeline updatePipeline = tektonPipeline.getItems().get(0);
                updatePipeline.setSpec(v1Beta1Pipeline.getSpec());
                object = customObjectsApi.replaceNamespacedCustomObject(
                        "tekton.dev",
                        "v1beta1",
                        pipeline.getNamespaceName(),
                        "pipelines",
                        updatePipeline.getMetadata().getName(),
                        updatePipeline,
                        null,
                        null
                );
            }
        } catch (ApiException e) {
//            log.info("pipeline:{}创建失败\napi返回信息:{},堆栈信息:", v1Beta1Pipeline.getMetadata().getName(), e.getResponseBody(), e);
            log.info("pipeline:{}创建失败\napi返回信息:{},堆栈信息:", e.getResponseBody(), e);
            throw new RuntimeException(e.getResponseBody());
        }
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeAdapter())
                .create();
        Type listType = new TypeToken<V1Beta1Pipeline>() {
        }.getType();
        String json = gson.toJson(object);
        return gson.fromJson(json, listType);
    }

    private static V1Beta1Pipeline getV1Beta1Pipeline(PipelineDTO pipeline) {


        V1Beta1Pipeline v1Beta1Pipeline = new V1Beta1Pipeline();
        v1Beta1Pipeline.setApiVersion("tekton.dev/v1beta1");
        v1Beta1Pipeline.setKind("Pipeline");
        V1ObjectMeta v1ObjectMeta = new V1ObjectMeta();
        v1ObjectMeta.setNamespace(pipeline.getNamespaceName());
        v1ObjectMeta.setName("pipeline-v3");
        v1Beta1Pipeline.setMetadata(v1ObjectMeta);

        V1Beta1PipelineSpec v1Beta1PipelineSpec = new V1Beta1PipelineSpec();

        List<V1Beta1ParamSpec> v1Beta1ParamSpecs = new ArrayList<>();
        V1Beta1ParamSpec v1Beta1ParamSpec1 = new V1Beta1ParamSpec();
        v1Beta1ParamSpec1.setName("url");
        v1Beta1ParamSpecs.add(v1Beta1ParamSpec1);
        V1Beta1ParamSpec v1Beta1ParamSpec2 = new V1Beta1ParamSpec();
        v1Beta1ParamSpec2.setName("revision");
        v1Beta1ParamSpecs.add(v1Beta1ParamSpec2);

        v1Beta1PipelineSpec.setParams(v1Beta1ParamSpecs);

        List<V1Beta1PipelineWorkspaceDeclaration> workspaces = new ArrayList<>();
        V1Beta1PipelineWorkspaceDeclaration workspace = new V1Beta1PipelineWorkspaceDeclaration();
        workspace.setName("git-source");

        workspaces.add(workspace);
        v1Beta1PipelineSpec.setWorkspaces(workspaces);

        List<V1Beta1PipelineTask> tasks = new ArrayList<>();
        V1Beta1PipelineTask task1 = new V1Beta1PipelineTask();
        task1.setName("fetch-from-git");
        V1Beta1TaskRef taskRef = new V1Beta1TaskRef();
        taskRef.setName("git-clone");
        task1.setTaskRef(taskRef);
        List<Param> params = new ArrayList<>();
        ParamValue pv1 = new ParamValue("$(params.url)");
        Param param1 = new Param("url", pv1);
        params.add(param1);
        ParamValue pv2 = new ParamValue("$(params.revision)");
        Param param2 = new Param("revision", pv2);
        params.add(param2);
        task1.setParams(params);
        List<V1Beta1PipelineTask.WorkspacePipelineTaskBinding> workspacePipelineTaskBindingList = new ArrayList<>();
        V1Beta1PipelineTask.WorkspacePipelineTaskBinding workspacePipelineTaskBinding = new V1Beta1PipelineTask.WorkspacePipelineTaskBinding();
        workspacePipelineTaskBinding.setName("output");
        workspacePipelineTaskBinding.setWorkspace("git-source");
        workspacePipelineTaskBindingList.add(workspacePipelineTaskBinding);
        task1.setWorkspaces(workspacePipelineTaskBindingList);
        tasks.add(task1);
        v1Beta1PipelineSpec.setTasks(tasks);
        v1Beta1Pipeline.setSpec(v1Beta1PipelineSpec);
        return v1Beta1Pipeline;
    }

    @Override
    public V1PipelineList getTektonPipeline(PipelineDTO pipeline) {
        K8sUtils.initApiClient(pipeline.getKubeConfig());
        CustomObjectsApi customObjectsApi = new CustomObjectsApi();
        V1PipelineList v1PipelineList = new V1PipelineList();
        String filedName = "";
        if (!StringUtils.isBlank(pipeline.getPipelineName())) {
            filedName = "metadata.name=" + pipeline.getPipelineName();
        }
        try {
            Object o = customObjectsApi.listNamespacedCustomObject(
                    "tekton.dev", "v1beta1", pipeline.getNamespaceName(),
                    "pipelines", null, null, null,
                    filedName, null,
                    null, null, null, null, null);

            Gson gson = new GsonBuilder()
                    .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeAdapter())
                    .create();
            String json = gson.toJson(o);
            Type listType = new TypeToken<V1PipelineList>() {
            }.getType();
            v1PipelineList = gson.fromJson(json, listType);
        } catch (ApiException e) {
            log.info("获取pipeline信息失败\napi返回信息:{},堆栈信息:", e.getResponseBody(), e);
            throw new RuntimeException(e.getResponseBody());
        }
        return v1PipelineList;
    }

    @Override
    public V1PipelineRunList getTektonPipelineRun(PipelineRunDTO pipeline) {
        log.info("获取pipelinerun:{}的信息", pipeline.getPipelineRunName());
        K8sUtils.initApiClient(pipeline.getKubeConfig());
        CustomObjectsApi customObjectsApi = new CustomObjectsApi();
        V1PipelineRunList v1PipelineRunList = new V1PipelineRunList();
        String filedName = null;
        if (!StringUtils.isBlank(pipeline.getPipelineRunName())) {
            filedName = "metadata.name=" + pipeline.getPipelineRunName();
        }
        try {
            Object o = customObjectsApi.listNamespacedCustomObject(
                    "tekton.dev", "v1beta1", pipeline.getNamespaceName(),
                    "pipelineruns", null, null, null,
                    filedName, null,
                    null, null, null, null, null);

            Gson gson = new GsonBuilder()
                    .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeAdapter())
                    .create();
            String json = gson.toJson(o);
            Type listType = new TypeToken<V1PipelineRunList>() {
            }.getType();
            v1PipelineRunList = gson.fromJson(json, listType);
        } catch (ApiException e) {
            log.info("获取pipelineRun信息失败\napi返回信息:{},堆栈信息:", e.getResponseBody(), e);
            throw new RuntimeException(e.getResponseBody());
        }
        //log.info("获取pipelinerun:{} 的信息成功，返回成功", pipeline.getPipelineRunName());
        log.info("获取pipelinerun的信息成功，返回成功");
        return v1PipelineRunList;
    }

    @Override
    public Boolean cancelPipelineRun(PipelineRunDTO pipelineRunDTO) {
        try {
            // 初始化 Kubernetes 客户端
            K8sUtils.initApiClient(pipelineRunDTO.getKubeConfig());
            CustomObjectsApi customObjectsApi = new CustomObjectsApi();

            // Tekton PipelineRun 的命名空间和名称
            String namespace = pipelineRunDTO.getNamespaceName();
            String name = pipelineRunDTO.getPipelineRunName();

            // 创建 JSON Patch 请求体
            String patchStr = "[{\"op\":\"replace\",\"path\":\"/spec/status\",\"value\":\"Cancelled\"}]";
            V1Patch patch = new V1Patch(patchStr);

            // 调用 CustomObjectsApi 停止 PipelineRun
            customObjectsApi.patchNamespacedCustomObject(
                    "tekton.dev",    // group
                    "v1beta1",      // version
                    namespace,      // namespace
                    "pipelineruns", // plural
                    name,             // name
                    patch,            // body
                    null,      // dryRun
                    null, // fieldManager
                    null        // force
            );

            System.out.println("PipelineRun stopped successfully");
            return true;
        } catch (ApiException e) {
            System.err.println("Exception when calling CustomObjectsApi");
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public V1Beta1PipelineRun createTektonPipelineRun(PipelineRunDTO pipeline) {
        VerifyUtil.verifyStringNotBlank(pipeline.getNamespaceName(), "未获取到命名空间的信息");
        VerifyUtil.verifyStringNotBlank(pipeline.getV1Beta1PipelineRunStr(), "未获取到命名空间的信息");

        K8sUtils.initApiClient(pipeline.getKubeConfig());
        // mock
        String v1Beta1PipelineStr = pipeline.getV1Beta1PipelineRunStr();
        V1Beta1PipelineRun v1Beta1PipelineRun = JSON.parseObject(v1Beta1PipelineStr, V1Beta1PipelineRun.class);

//        V1Beta1PipelineRun v1Beta1PipelineRun = getV1Beta1PipelineRun(pipeline);

        CustomObjectsApi customObjectsApi = new CustomObjectsApi();
        Object object = null;
        try {
            object = customObjectsApi.createNamespacedCustomObject(
                    "tekton.dev",
                    "v1beta1",
                    pipeline.getNamespaceName(),
                    "pipelineruns",
                    v1Beta1PipelineRun, null, null, null
            );

        } catch (ApiException e) {
//            log.info("pipeline:{}创建失败\napi返回信息:{},堆栈信息:", v1Beta1Pipeline.getMetadata().getName(), e.getResponseBody(), e);
            log.info("pipelineRun:{}创建失败\napi返回信息:{},堆栈信息:", e.getResponseBody(), e);
            throw new RuntimeException(e.getResponseBody());
        }
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeAdapter())
                .create();
        String json = gson.toJson(object);
        Type listType = new TypeToken<V1Beta1PipelineRun>() {
        }.getType();
        return gson.fromJson(json, listType);
    }

    private static V1Beta1PipelineRun getV1Beta1PipelineRun(PipelineRunDTO pipeline) {
        V1Beta1PipelineRun v1Beta1PipelineRun = new V1Beta1PipelineRun();
        v1Beta1PipelineRun.setApiVersion("tekton.dev/v1beta1");
        v1Beta1PipelineRun.setKind("PipelineRun");

        V1ObjectMeta v1ObjectMeta = new V1ObjectMeta();
        v1ObjectMeta.setNamespace(pipeline.getNamespaceName());
        v1ObjectMeta.setName("pipelinerun-v31");
        v1Beta1PipelineRun.setMetadata(v1ObjectMeta);

        V1Beta1PipelineRunSpec spec = new V1Beta1PipelineRunSpec();
        V1Beta1PipelineRunSpec.PipelineRef pipelineRef = new V1Beta1PipelineRunSpec.PipelineRef();
        pipelineRef.setName("pipeline-v3");
        spec.setPipelineRef(pipelineRef);

        List<Param> params = new ArrayList<>();
        Param param1 = new Param();
        param1.setName("url");
        ParamValue paramValue1 = new ParamValue("https://oauth2:gAvYKYeVDhxGt9sLtDfv@gitlab.xuelangyun.com/appDev/rdp-test.git");
        param1.setValue(paramValue1);
        params.add(param1);

        Param param2 = new Param();
        param2.setName("revision");
        ParamValue paramValue2 = new ParamValue("master");
        param2.setValue(paramValue2);
        params.add(param2);
        spec.setParams(params);

        List<V1Beta1WorkspaceBinding> workspaces = new ArrayList<>();
        V1Beta1WorkspaceBinding workspace1 = new V1Beta1WorkspaceBinding();
        workspace1.setName("git-source");
        V1SecretVolumeSource secret = new V1SecretVolumeSource();
        secret.setSecretName("docker-credentials");
        workspace1.setSecret(secret);
        workspaces.add(workspace1);
        V1Beta1WorkspaceBinding workspace2 = new V1Beta1WorkspaceBinding();
        workspace2.setName("output");
//        V1EmptyDirVolumeSource emptyDirVolumeSource = new V1EmptyDirVolumeSource();
//        workspace2.setEmptyDir(emptyDirVolumeSource);
        V1PersistentVolumeClaimVolumeSource pvc = new V1PersistentVolumeClaimVolumeSource();
        pvc.setClaimName("git-pvc");
        workspace2.setPersistentVolumeClaim(pvc);
        workspaces.add(workspace2);

        spec.setWorkspaces(workspaces);
        v1Beta1PipelineRun.setSpec(spec);
        return v1Beta1PipelineRun;
    }
}
